const {EnumRole, EnumBehavior, EnumHarvestMode} = require("./Enum");
const {findStore, findBuild, findLink, findEnergyStore} = require("./Find");
const {harvest, butler, engine, defense} = require("./Role");
const {getPixel} = require("./Behavior");
const {towerBehavior, distributeTower, distributeLink} = require("./Build");
const {spawning, spawnMonitor} = require("./Spawn");
module.exports.distributeAll = room => {
    let roomCreepList = room.find(FIND_MY_CREEPS, {filter: creep => !creep.spawning});
    let storeList = findStore(room);
    let emptyStoreList = storeList.filter(store => store.freeStore());
    if (Game.time % 10 === 0) {
        spawning(room, emptyStoreList);
        bindRoomLink(room);
    }
    if (Game.time % 500 === 0) {
        for (const name in Memory.creeps) {
            if (!Game.creeps[name]) {
                delete Memory.creeps[name];
            }
        }
    }
    let harvestList = [];
    let butlerList = [];
    let engineList = [];
    let defenseList = [];
    for (let creep of roomCreepList) {
        let role = creep.memory.role;
        if (role === EnumRole.Harvest) {
            harvestList.push(creep);
            continue;
        }
        if (role === EnumRole.Butler) {
            butlerList.push(creep);
            continue;
        }
        if (role === EnumRole.Engineer) {
            engineList.push(creep);
            continue;
        }
        if (role === EnumRole.OutEngineer && creep.memory.workRoom === room.name) {
            engineList.push(creep);
            continue;
        }
        if (role === EnumRole.Defense) {
            defenseList.push(creep);
            continue;
        }
    }
    let towerList = findBuild(room, STRUCTURE_TOWER);
    initRoomMemory(room, butlerList);
    let emptyBaseList = emptyStoreList.filter(store => store.my && store.structureType === STRUCTURE_EXTENSION || store.structureType === STRUCTURE_SPAWN || (store.structureType === STRUCTURE_TOWER && store.usedStore() / store.maxStore() < 0.75))
    let emptyNoBaseList = emptyStoreList.filter(store => store.structureType === STRUCTURE_STORAGE || store.structureType === STRUCTURE_CONTAINER);
    let usedStoreList = findEnergyStore(room).filter(build => build.usedStore() > 0);
    let repairBuildList = [];
    if (room.memory.canRepair) {
        repairBuildList = room.find(FIND_STRUCTURES, {
            filter: build => {
                if(build.structureType===STRUCTURE_CONTROLLER) return false;
                if (build.hits > build.hitsMax * 0.8) return false;// 耐久Full
                if (build.structureType === STRUCTURE_ROAD && build.hits > build.hitsMax / 2) return false;
                if (build.structureType === STRUCTURE_WALL && build.isActive() && (build.hits > 50000 * room.controller.level || towerList.length === 0 || usedStoreList.length<3)) return false;
                return !(build.structureType === STRUCTURE_RAMPART && build.hits > 30000 * room.controller.level);

            }
        })
    }
    let freeButlerList = butlerList.filter(butler => butler.memory.behavior === EnumBehavior.Free);
    let freeEngineList = engineList.filter(engine => engine.memory.behavior !== EnumBehavior.UpController);
    let workButlerEngineList=freeEngineList;
    if(workButlerEngineList.length>0){
        workButlerEngineList=freeEngineList.slice(0,1);
    }
    //Engineer
    distributeEngineer(room, freeEngineList, towerList, repairBuildList);
    //Butler
    replenishEnergyBuild(room, freeButlerList, workButlerEngineList, emptyBaseList, emptyNoBaseList);


    //Build
    //Tower
    distributeTower(room, roomCreepList, repairBuildList);
    //Link
    distributeLink(room, butlerList);

    //last execute room creep behavior
    for (let creep of harvestList) {
        harvest(creep)
    }
    for (let creep of butlerList) {
        butler(creep);
    }
    for (let creep of engineList) {
        engine(creep);
    }
    for (let tower of towerList) {
        towerBehavior(tower);
    }
    for (let defenseCreep of defenseList) {
        defense(defenseCreep);
    }

    getPixel();
}

const initRoomMemory = (room, butlerList) => {
    if (room.memory.canRepair === undefined) {
        room.memory.canRepair = false
    }
    if (room.memory.canBuild === undefined) {
        room.memory.canBuild = false
    }
    if (room.memory.mode === undefined) {
        room.memory.mode = EnumHarvestMode.HarvestAndTrans
    }
    if (Game.time % 30 === 0) {
        //monitor repair
        let repairList = room.find(FIND_STRUCTURES, {
            filter: build => {
                if(build.structureType===STRUCTURE_CONTROLLER) return false;
                if (build.hits > build.hitsMax * 0.8) return false;// 耐久Full
                if (build.structureType === STRUCTURE_CONTROLLER) return false
                if (build.structureType === STRUCTURE_ROAD && build.hits > build.hitsMax / 2) return false;
                if (build.structureType === STRUCTURE_WALL && build.isActive() && build.hits > 50000 * room.controller.level || room.find(FIND_MY_STRUCTURES).filter(build => build.structureType === STRUCTURE_TOWER).length === 0) return false;
                return !(build.structureType === STRUCTURE_RAMPART && build.hits > 30000 * room.controller.level);

            }
        })
        if (butlerList.length > 0) {
            room.memory.mode = EnumHarvestMode.OnlyHarvest;
        } else {//not exist Butler
            //modify room mode
            room.memory.mode = EnumHarvestMode.HarvestAndTrans;
        }
        room.memory.canRepair = repairList.length > 0;
        //monitor build
        let prepareBuildList = room.find(FIND_MY_CONSTRUCTION_SITES);
        room.memory.canBuild = prepareBuildList.length > 0;
        //monitor spawn
        spawnMonitor(room);
    }
}

const distributeEngineer = (room, freeEngineList, towerList, repairList) => {
    if (room.controller.ticksToDowngrade < 3000) {
        for (let engine of freeEngineList) {
            engine.bindBehavior(EnumBehavior.UpController, room.controller.id);
        }
        return;
    }
    let prepareBuildList = [];
    if (room.memory.canBuild) {
        prepareBuildList = room.find(FIND_MY_CONSTRUCTION_SITES);
        let basePrepareBuildList = prepareBuildList.filter(build => build.structureType === STRUCTURE_SPAWN)
        if (basePrepareBuildList.length > 0) {
            building(basePrepareBuildList, freeEngineList);
            return;
        }
    }
    //RepairBuild
    if (towerList.length <= 0 && repairList.length > 0) {
        repairBuild(repairList, freeEngineList)
        return;
    }
    //Building
    if (prepareBuildList.length > 0) {
        //priority first Spawn or extension
        let basePrepareBuildList = prepareBuildList.filter(build => build.structureType === STRUCTURE_SPAWN || build.structureType === STRUCTURE_EXTENSION);
        if (basePrepareBuildList.length > 0) {
            building(basePrepareBuildList, freeEngineList);
            return;
        }
        //priority second energy Store
        let energyStoreBuildList = prepareBuildList.filter(build => build.structureType === STRUCTURE_CONTAINER || build.structureType === STRUCTURE_STORAGE);
        if (energyStoreBuildList.length > 0) {
            building(energyStoreBuildList, freeEngineList);
            return;
        }
        building(prepareBuildList, freeEngineList);
        return;
    }
    //up controller
    for (let engine of freeEngineList) {
        engine.bindBehavior(EnumBehavior.UpController, engine.room.controller.id);
    }
}


function repairBuild(repairList, engineList) {
    for (let i = 0; i < engineList.length; i++) {
        let creep = engineList[i];
        creep.bindBehavior(EnumBehavior.RepairBuild, repairList[0].id);
    }
}

function building(prepareBuildList, engineList) {
    for (let creep of engineList) {
        creep.bindBehavior(EnumBehavior.Building, prepareBuildList[0].id);
    }
}

function replenishEnergyBuild(room, freeButlerList, freeEngineList, emptyBaseList, emptyNoBaseList) {
    /**
     * before:
     * 1.Store need ReplenishEnergy
     * 2.Butler store is not empty
     * 3.priority replenish Spawn or extension
     */
        //if base is empty,engineer is butler
    let allFreeList;
    if (emptyBaseList.length > 0) {
        allFreeList = [...freeButlerList, ...freeEngineList];
    } else {
        allFreeList = [...freeButlerList]
    }
    let mustNeedTowerList = room.find(FIND_STRUCTURES, {filter: build => build.structureType === STRUCTURE_TOWER && build.usedStore() < build.maxStore() * 0.25});
    if (mustNeedTowerList.length > 0 && allFreeList.length > 0) {
        let needTower = mustNeedTowerList.splice(0, 1);
        let freeButler = allFreeList.splice(0, 1)[0];
        freeButler.bindBehavior(EnumBehavior.ReplenishBuild, needTower[0].id);
    }
    if (room.storage !== undefined) {
        let haveOtherStoreList = findStore(room).filter(build => {
            let haveOther = false;
            for (let resourceType in build.store) {
                if (resourceType !== RESOURCE_ENERGY) {
                    haveOther = true;
                    break;
                }
            }
            return build.structureType === STRUCTURE_CONTAINER && haveOther;
        })
        if (haveOtherStoreList.length > 0) {
            for (let i = 0; i < Math.min(haveOtherStoreList.length, freeButlerList.length); i++) {
                freeButlerList[i].bindBehavior(EnumBehavior.TransMineral, haveOtherStoreList[i].id);
                allFreeList.splice(i, 1);
            }
        }
    }
    if (allFreeList.length > 0) {
        //priority Spawning/extension/half energy tower
        if (emptyBaseList.length > 0) {
            let minReplySize = Math.min(allFreeList.length, emptyBaseList.length);
            for (let i = 0; i < minReplySize; i++) {
                allFreeList[i].bindBehavior(EnumBehavior.ReplenishBuild, emptyBaseList[i].id);
            }
            return;
        }

        let dropResourceList = room.find(FIND_DROPPED_RESOURCES);
        if (emptyNoBaseList.length > 0 && dropResourceList.length > 0) {
            let minReplySize = Math.min(allFreeList.length, emptyNoBaseList.length, dropResourceList.length);
            for (let i = 0; i < minReplySize; i++) {
                allFreeList[i].bindBehavior(EnumBehavior.ReplenishBuild, emptyNoBaseList[i].id);
            }
            return;
        }
    }
    if(freeButlerList.length>0){
        //if terminal freeStore > 50K
        //meanwhile storage have other energy
        if(room.storage&&room.terminal&&room.terminal.freeStore()>room.terminal.maxStore()/6&&room.storage.usedStore()!==room.storage.maxStore()-room.storage.freeStore()){
            let moreOtherResource="";
            let maxAmount=0;
            for (let storeKey in room.storage.store) {
                if(storeKey!==RESOURCE_ENERGY){
                    let amount=room.storage.usedStore(storeKey);
                    if(amount>maxAmount){
                        maxAmount=amount;
                        moreOtherResource=storeKey;
                    }
                }
            }
            if(moreOtherResource!==""){
                for (let butler of freeButlerList) {
                    butler.bindBehavior(EnumBehavior.TransMineralToTerminal,room.terminal.id);
                    butler.memory.transMineralType=moreOtherResource;
                }
            }
            return;
        }

        //if storage have energy
        //mean container is not full
        if(room.storage&&room.storage.usedStore()>30*1000){
            let needReplenishList = findBuild(room,STRUCTURE_CONTAINER).filter(build=>build.usedStore()<1200);
            let minReplenishSize=Math.min(needReplenishList.length,freeButlerList.length);
            for (let i = 0; i < minReplenishSize; i++) {
                freeButlerList[i].bindBehavior(EnumBehavior.TransContainer, needReplenishList[i].id);
            }
            return;
        }
    }
}

function bindRoomLink(room) {
    let roomLink = findLink(room);
    if (roomLink.length <= 0) {
        return
    }
    if (!room.memory.baseLink) {
        let baseLink = room.storage.pos.findClosestByRange(roomLink);
        room.memory.baseLink = baseLink.id;
    }
    if (roomLink.length >= 4 && !room.memory.upLink) {
        let upLink = room.controller.pos.findClosestByRange(roomLink);
        room.memory.upLink = upLink.id;
    }
}